using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using MindBreakerResources;
using MindBreaker.LevelManagement;
using MindBreaker.GameObjects;

namespace MindBreaker
{
    /// <summary>
    /// Type principal pour votre jeu
    /// </summary>
    public class MindBreaker : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Level currentLevel;
        BottomBar currentBar;
        SoundEffect gameSound;
        

        private int currentBallCount;

        public MindBreaker()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            this.TargetElapsedTime = TimeSpan.FromMilliseconds(10);
            this.currentBallCount = 2;
        }

        /// <summary>
        /// Permet au jeu d’effectuer l’initialisation nécessaire pour l’exécution.
        /// Il peut faire appel aux services et charger tout contenu
        /// non graphique. Calling base.Initialize énumère les composants
        /// et les initialise.
        /// </summary>
        protected override void Initialize()
        {
            // Initialisation du TextureManager et du physicengine
            TextureManager.getInstance(this);
            PhysicEngine physicEngine = PhysicEngine.getInstance();

            // Chargement du niveau
            this.currentLevel = new Level(this, @"levels\level_default");

            // Création des balles
            int nbBalle = this.currentBallCount, width = 400 - 40 * nbBalle/2;
            for (int i = 0; i < nbBalle; i++) {
                Ball currentBall = new Ball(this, width, 300);
                // Ajout des balles en reference
                physicEngine.Reference.Add(currentBall);
                // Ajout des balles en tant qu'objet au moteur (pour gérer les collisions entre balles)
                physicEngine.add(currentBall);
                width += 40;
            }

            // Création de la barre
            this.currentBar = new BottomBar(this, 330, 530, 0, 0);
            physicEngine.add(this.currentBar);

            base.Initialize();
        }

        /// <summary>
        /// LoadContent est appelé une fois par partie. Emplacement de chargement
        /// de tout votre contenu.
        /// </summary>
        protected override void LoadContent()
        {
            // Créer un SpriteBatch, qui peut être utilisé pour dessiner des textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            
            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 600;
            graphics.ApplyChanges();

            //Chargement du fond sonore permanent
            this.gameSound = Content.Load<SoundEffect>(@"sounds\soundGame");

            //Permanence du fond sonore
            SoundEffectInstance instance = this.gameSound.CreateInstance();
            instance.IsLooped = true;
            instance.Volume = TextureManager.SOUND_VOLUME_MUSIC;
            instance.Play();

            base.LoadContent();

        }

        /// <summary>
        /// UnloadContent est appelé une fois par partie. Emplacement de déchargement
        /// de tout votre contenu.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Déchargez le contenu non ContentManager ici
        }

        /// <summary>
        /// Permet au jeu d’exécuter la logique de mise à jour du monde,
        /// de vérifier les collisions, de gérer les entrées et de lire l’audio.
        /// </summary>
        /// <param name="gameTime">Fournit un aperçu des valeurs de temps.</param>
        protected override void Update(GameTime gameTime)
        {
            // Permet au jeu de se fermer
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            KeyboardState keyboard = Keyboard.GetState();
            if (keyboard.IsKeyDown(Keys.NumPad2)) {
                this.resetGameWithBalls(2);
            } else if(keyboard.IsKeyDown(Keys.NumPad4)) {
                this.resetGameWithBalls(4);
            } else if(keyboard.IsKeyDown(Keys.NumPad6)) {
                this.resetGameWithBalls(6);
            } else if(keyboard.IsKeyDown(Keys.NumPad8)) {
                this.resetGameWithBalls(8);
            } else {
                // Default game update
                PhysicEngine.getInstance().update();
                base.Update(gameTime);
            }
        }

        protected void resetGameWithBalls(int nbBall)
        {
            this.currentBallCount = nbBall;
            this.Components.Clear();
            PhysicEngine.destroyInstance();
            this.Initialize();
        }

        /// <summary>
        /// Appelé quand le jeu doit se dessiner.
        /// </summary>
        /// <param name="gameTime">Fournit un aperçu des valeurs de temps.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            base.Draw(gameTime);
        }
    }
}
